package com.example.opencv_demo.activity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.opencv_demo.R;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDouble;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private ImageView imageView;
    private Bitmap grayBitmap;
    private Bitmap srcBitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = findViewById(R.id.img);
        srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.jin);//构建灰度 RGB 图片
//设置显示
        imageView.setImageBitmap(srcBitmap);
    }

    /**
     * 图片灰度化
     *
     * @param view
     */
    public void btnClick(View view) {
        Mat rgbMat = new Mat();
        Mat grayMat = new Mat();

        grayBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(),
                Bitmap.Config.RGB_565);
//将资源图片转化为 Mat 类资源
        Utils.bitmapToMat(srcBitmap, rgbMat);//convert original bitmap to Mat, R G B.
//将图片灰度化
        Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);
//添加文字
        Imgproc.putText(grayMat, "hello openCv"
                , new Point(100, 200), Core.FONT_HERSHEY_COMPLEX
                , 5, new Scalar(255, 255, 255), 5);
//将灰度 Mat 转换为灰度 BitMap 资源
        Utils.matToBitmap(grayMat, grayBitmap);
        grayMat.release();
        rgbMat.release();
        imageView.setImageBitmap(grayBitmap);
    }




    /**
     * 原图显示
     *
     * @param view
     */
    public void btn0Click(View view) {
        imageView.setImageBitmap(srcBitmap);
    }

    /**
     * 去透明后灰度化
     *
     * @param view
     */
    public void btn1Click(View view) {

        Mat rgbMat = new Mat();
        Mat grayMat = new Mat();
        grayBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);

        int with = grayBitmap.getWidth();
        int height = grayBitmap.getHeight();
        int[] pixs = new int[with * height];
        int length = pixs.length;
        grayBitmap.getPixels(pixs, 0, with, 0, 0, with, height);
        for (int i = 0; i < length; i++) {
            int a = Color.alpha(pixs[i]);
            int r = Color.red(pixs[i]);
            int g = Color.green(pixs[i]);
            int b = Color.blue(pixs[i]);
            r = (a * r / 255 + (255) * (255 - a) / 255);
            g = (a * g / 255 + (255) * (255 - a) / 255);
            b = (a * b / 255 + (255) * (255 - a) / 255);
            pixs[i] = Color.argb(255, r, g, b);
        }
        grayBitmap.setPixels(pixs, 0, with, 0, 0, with, height);


        imageView.setImageBitmap(grayBitmap);


    }

    /**
     * Mat操作之图片去透明
     *
     * @param view
     */
    public void btn2Click(View view) {

        Mat rgbMat = new Mat();

        grayBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);

        Utils.bitmapToMat(grayBitmap, rgbMat, true);//必须传ture 否则得到的Mat会受透明度影响

        int with = rgbMat.cols();
        int height = rgbMat.rows();
        byte[] data = new byte[4 * with];
        for (int col = 0; col < height; col++) {
            rgbMat.get(col, 0, data);
            for (int row = 0; row < with; row++) {
                //byte 取值范围在-128~127之间
                // 正数补码为其本身；负数补码为其绝对值各位取反加1
                // 如:+3的二进制为0000 0011
                //-3的二进制编码计算 首先对0000 0011取反的得1111 1100 ,然后再对编码加1
                //所以-3的二进制编码为1111 1101
                //所以颜色值为255时,对应的byte值为-1

                //将byte值 转成颜色的int值  d0,d1,d2分别对应的r,g,b三种颜色 d3为不透明度
                int d0 = (data[row * 4] >= 0) ? data[row * 4] : 256 + data[row * 4];
                int d1 = (data[1 + row * 4] >= 0) ? data[1 + row * 4] : 256 + data[1 + row * 4];
                int d2 = (data[2 + row * 4] >= 0) ? data[2 + row * 4] : 256 + data[2 + row * 4];
                int d3 = (data[3 + row * 4] >= 0) ? data[3 + row * 4] : 256 + data[3 + row * 4];

                data[row * 4] = (byte) ((d3 * d0 / 255 + (255) * (255 - d3) / 255));
                data[1 + row * 4] = (byte) ((d3 * d1 / 255 + (255) * (255 - d3) / 255));
                data[2 + row * 4] = (byte) ((d3 * d2 / 255 + (255) * (255 - d3) / 255));
                data[3 + row * 4] = -1;


            }
            rgbMat.put(col, 0, data);
        }

        Utils.matToBitmap(rgbMat, grayBitmap, true); //一定要加ture 否则得到的BitMap会受透明度影响
        rgbMat.release();


        imageView.setImageBitmap(grayBitmap);


    }

    /**
     * mat通道的分离合并
     *
     * @param view
     */
    public void btn3Click(View view) {

        Mat rgbMat = new Mat();
        grayBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
        Utils.bitmapToMat(grayBitmap, rgbMat, true);
        List<Mat> list = new ArrayList<>();
        //通道分离
        Core.split(rgbMat, list);

        List<Mat> list1 = new ArrayList<>();
        list1.add(list.get(0));
        list1.add(list.get(1));
        list1.add(list.get(1));//添加重复通道 为了查看效果差异
        list1.add(list.get(3));

        //通道合并
        Core.merge(list1, rgbMat);

        Utils.matToBitmap(rgbMat, grayBitmap, true);
        rgbMat.release();


        imageView.setImageBitmap(grayBitmap);


    }

    public void btn4Click(View view) {
        Mat rgbMat = new Mat();
        grayBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
        Utils.bitmapToMat(grayBitmap, rgbMat, true);
        Mat grayMat = new Mat();
        //灰度化
        Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_BGR2GRAY);

        MatOfDouble means = new MatOfDouble();
        MatOfDouble stddevs = new MatOfDouble();
        //计算通道的均值和标准差
        Core.meanStdDev(grayMat, means, stddevs);
        double[] mean = means.toArray();
        double[] stddev = stddevs.toArray();
        Log.i(TAG, "btn4Click: mean=" + mean[0] + "  stddev=" + stddev[0]);

        int with = grayMat.cols();
        int height = grayMat.rows();
        byte[] data = new byte[with * height];
        grayMat.get(0, 0, data);
        int pv = 0;
        //根据均值 二极化
        int t = (int) mean[0];
        for (int i = 0; i < with * height; i++) {
            pv = data[i] & 0xff;
            if (pv > t) {
                data[i] = -1;
            } else {
                data[i] = 0;
            }
        }
        grayMat.put(0, 0, data);
        Utils.matToBitmap(grayMat, grayBitmap, true);
        rgbMat.release();
        grayMat.release();
        imageView.setImageBitmap(grayBitmap);
    }

    /**
     * 提高对比度
     *
     * @param view
     */
    public void btn5Click(View view) {
        Mat rgbMat = new Mat();
        grayBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
        Utils.bitmapToMat(grayBitmap, rgbMat, true);
        Mat mat = new Mat();
        //降亮度
        Core.subtract(rgbMat, new Scalar(50, 50, 50), mat);
        Mat mat1 = new Mat();
        //提升对比度
        Core.multiply(mat, new Scalar(1.2, 1.2, 1.2, 1), mat1);

        Utils.matToBitmap(mat1, grayBitmap, true);
        rgbMat.release();
        imageView.setImageBitmap(grayBitmap);
    }

    /**
     * 基于权重叠加
     *
     * @param view
     */
    public void btn6Click(View view) {
        Mat rgbMat = new Mat();
        grayBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
        int with = grayBitmap.getWidth();
        int height = grayBitmap.getHeight();
        int[] pixs = new int[with * height];
        int length = pixs.length;
        grayBitmap.getPixels(pixs, 0, with, 0, 0, with, height);
        for (int i = 0; i < length; i++) {
            int a = Color.alpha(pixs[i]);
            int r = Color.red(pixs[i]);
            int g = Color.green(pixs[i]);
            int b = Color.blue(pixs[i]);
            r = (a * r / 255 + (255) * (255 - a) / 255);
            g = (a * g / 255 + (255) * (255 - a) / 255);
            b = (a * b / 255 + (255) * (255 - a) / 255);
            pixs[i] = Color.argb(255, r, g, b);
        }
        grayBitmap.setPixels(pixs, 0, with, 0, 0, with, height);
        Bitmap bitmap = grayBitmap.copy(Bitmap.Config.RGB_565, true);
        Utils.bitmapToMat(bitmap, rgbMat);
        Mat mat = Mat.zeros(rgbMat.size(), rgbMat.type());

        Mat mat1 = new Mat();
        double a = 0.8d;
        //根据权重
        Core.addWeighted(rgbMat, a, mat, 1 - a, 0, mat1);

        Utils.matToBitmap(mat1, bitmap);

        imageView.setImageBitmap(bitmap);

    }

    /**
     * 取反操作
     *
     * @param view
     */
    public void btn7Click(View view) {
        Mat rgbMat = new Mat();
        grayBitmap = srcBitmap.copy(Bitmap.Config.RGB_565, true);
        Utils.bitmapToMat(grayBitmap, rgbMat);

        Mat mat1 = new Mat();
        //取反
        Core.bitwise_not(rgbMat, mat1);

        Utils.matToBitmap(mat1, grayBitmap);
        rgbMat.release();
        imageView.setImageBitmap(grayBitmap);
    }

    private void copy(Mat src,Mat dst){
        int with=src.cols();
        int height=src.rows();
        for (int i = 0; i < height; i++) {
            byte[] data=new byte[with*src.channels()];
            src.get(i,0,data);
            dst.put(i,0,data);
        }

    }

    /**
     * 与运算操作
     *
     * @param view
     */
    public void btn8Click(View view) {
        twoMatOperation(1);
    }

    private void twoMatOperation(int Op) {
        Mat rgbMat = new Mat();
        Mat rgbMat2 = new Mat();
        grayBitmap = srcBitmap.copy(Bitmap.Config.RGB_565, true);
        Bitmap srcBitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.ju1);
        Bitmap bitmap=srcBitmap2.copy(Bitmap.Config.RGB_565, true);
        Utils.bitmapToMat(grayBitmap, rgbMat);
        Utils.bitmapToMat(bitmap, rgbMat2);
        int with=Math.max(rgbMat.cols(),rgbMat2.cols());
        int height=Math.max(rgbMat.rows(),rgbMat2.rows());
        Mat mat1=new Mat(height,with,rgbMat.type());
        Mat mat2=new Mat(height,with,rgbMat.type());
        copy(rgbMat,mat1);
        copy(rgbMat2,mat2);
        Mat mat = new Mat();
        switch (Op){
            case 1:
                Core.bitwise_and(mat1, mat2, mat);//与运算
                break;
            case 2:
                Core.bitwise_or(mat1,mat2,mat);//或运算
                break;
            case 3:
                Core.bitwise_xor(mat1,mat2,mat);//异或运算  可看做叠加后取反
        }

        Bitmap bitmap1=Bitmap.createBitmap(with,height,Bitmap.Config.RGB_565);
        Utils.matToBitmap(mat, bitmap1);
        mat.release();
        mat1.release();
        mat2.release();
        rgbMat.release();
        rgbMat2.release();

        imageView.setImageBitmap(bitmap1);
        imageView.invalidate();
    }

    public void btn9Click(View view) {
        twoMatOperation(2);
    }

    public void btn10Click(View view) {
        twoMatOperation(3);
    }

    /**
     * 高斯随机产生mat图像 进行归一化后进行显示
     * @param view
     */
    public void btn11Click(View view) {
        Mat src=Mat.zeros(400,400, CvType.CV_32FC3);
        float[] data=new float[400*400*3];
        Random random=new Random();
        for (int i = 0; i <data.length ; i++) {
            data[i]= (float) random.nextGaussian();
        }
        src.put(0,0,data);

        Mat mat=new Mat();
        //归一化
        Core.normalize(src,mat,0,255,Core.NORM_MINMAX,-1,new Mat());
        Mat dst8u=new Mat();
        //类型转化
        mat.convertTo(dst8u,CvType.CV_8UC3);
        Bitmap bitmap=Bitmap.createBitmap(400,400,Bitmap.Config.RGB_565);
        Utils.matToBitmap(dst8u,bitmap);
        imageView.setImageBitmap(bitmap);
    }

    /**
     * 均值模糊
     * @param view
     */
    public void btn12Click(View view) {
        grayBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
        Mat srcMat=new Mat();
        Utils.bitmapToMat(grayBitmap,srcMat,true);
        Mat mat=new Mat();
        //均值模糊
        Imgproc.blur(srcMat,mat,new Size(15,15),new Point(-1,-1));
        Utils.matToBitmap(mat,grayBitmap,true);
        imageView.setImageBitmap(grayBitmap);
    }

    /**
     * 高斯模糊
     * @param view
     */
    public void btn13Click(View view) {
        grayBitmap = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
        Mat srcMat=new Mat();
        Utils.bitmapToMat(grayBitmap,srcMat,true);
        Mat mat=new Mat();
        //高斯模糊  size里面必须是奇数
        Imgproc.GaussianBlur(srcMat,mat,new Size(15,15),0);
        Utils.matToBitmap(mat,grayBitmap,true);
        imageView.setImageBitmap(grayBitmap);
    }
}